package com.simpou.tests.persistence;

import com.simpou.commons.model.entity.BaseEntity;
import com.simpou.commons.model.entity.IdentifiableEntity;
import com.simpou.commons.persistence.dao.TypedDAO;
import com.simpou.tests.persistence.exception.DaoException;

import java.util.ArrayList;
import java.util.List;

/**
 * Operações úteis sobre entidades utilizando DAOs, valores aleatórios são
 * utilizados.
 *
 * @author Jonas Pereira
 * @since 2011-06-10
 * @version 2012-06-11
 */
public class EntitiesTester {

    /**
     * Realiza as operações CRUD básicas sobre uma entidade usando dados
     * aleatórios.
     *
     * @param entityClass Classe da entidade. Usada para gerar novas instâncias
     * via reflexão.
     * @param dao Para realizar as operações DAO necessárias.
     * @return Exceções ocorridas durante o processo se houverem. Valor não
     * null.
     * @throws java.lang.InstantiationException Pode ocorrer durante
     * instanciação via reflexão.
     * @throws java.lang.IllegalAccessException Pode ocorrer durante
     * instanciação via reflexão.
     * @param <T> a T object.
     */
    public static <T extends IdentifiableEntity, E extends TypedDAO<T>> List<DaoException> doRandomCrud(
        final Class<T> entityClass, final TypedDAO<T> dao)
        throws InstantiationException, IllegalAccessException {
        List<DaoException> exceptions = new ArrayList<DaoException>();
        T entity = null;

        // create
        entity = newRandomEntity(entityClass);

        try {
            entity = dao.create(entity);
            dao.flush();
        } catch (Exception ex) {
            exceptions.add(new DaoException(
                    DaoException.DaoExceptionType.CREATE, entityClass, ex));

            return exceptions;
        }

        // update
        try {
            entity.fillRandom();
            entity = dao.update(entity);
            dao.flush();
        } catch (Exception ex) {
            exceptions.add(new DaoException(
                    DaoException.DaoExceptionType.UPDATE, entityClass, ex));
        }

        // retrieve single
        try {
            T entityRet = (T) dao.getSingle(entity.getClass(), entity.identity());
        } catch (Exception ex) {
            exceptions.add(new DaoException(
                    DaoException.DaoExceptionType.RETRIEVE_SINGLE, entityClass,
                    ex));
        }

        // retrieve list
        try {
            List<T> list = dao.getList();

            if (!list.contains(entity)) {
                exceptions.add(new DaoException(
                        DaoException.DaoExceptionType.RETRIEVE_LIST,
                        entityClass, "List was not retrieved correctly."));
            }
        } catch (Exception ex) {
            exceptions.add(new DaoException(
                    DaoException.DaoExceptionType.RETRIEVE_LIST, entityClass, ex));
        }

        // delete
        try {
            dao.delete(entity);
            dao.flush();
        } catch (Exception ex) {
            exceptions.add(new DaoException(
                    DaoException.DaoExceptionType.DELETE, entityClass, ex));
        }

        return exceptions;
    }

    /**
     * @param <T> Tipo da entidade a ser gerada.
     * @param entityClass Classe da entidade a ser gerada.
     * @return Nova instância de entidade preenchida aleatoriamente.
     * @throws InstantiationException Se houver.
     * @throws IllegalAccessException Se houver.
     */
    public static <T extends BaseEntity> T newRandomEntity(
        final Class<T> entityClass)
        throws InstantiationException, IllegalAccessException {
        T entity = entityClass.newInstance();
        entity.fillRandom();

        return entity;
    }
}
